#!/usr/bin/env python
# -*- mode: python; coding: utf-8; -*-
##--------------------------------------------------------------------------##
##
## Copyright (C) 1998-2003 Markus Oberhumer <markus@oberhumer.com>
## Copyright (C) 2003 Mt. Hood Playing Card Co.
## Copyright (C) 2005-2010 Skomoroh <skomoroh@users.sourceforge.net>
## Copyright (C) 2010-2013 Jeremy Austin-Bardo <tjaustinbardo@gmail.com>
##
## This program is free software: you can redistribute it and/or modify
## it under the terms of the GNU General Public License as published by
## the Free Software Foundation, either version 3 of the License.
##
## This program is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
## GNU General Public License for more details.
##
## You should have received a copy of the GNU General Public License
## along with this program.  If not, see <http://www.gnu.org/licenses/>.
##
##-- G05 -- S04 ------------------------------------------------------------##
__all__ = []

from .. import autostacks
from .. import formlib as layout
from .. import pilelib as stack
from .. import stackfill as fill
from ..gamelib import info as gi, state, game
from ..hint import DefaultHint, DropbyCautiousHint
from ..packlib import info as cs, place
from ..pilelib import move as a_move

StackWrapper = stack.StackWrapper
GT, SL = gi.GT, gi.SL


class Hemispheres_Hint(DefaultHint):

    def shall_move_pile(self, from_stack, to_stack, pile, rpile):
        """
        shall_move_pile(from_stack:Stack, to_stack:Stack, pile:seq(Card ...),
          rpile:seq(Card ...)) -> bool

        Returns **pile** builds on **to_stack**?

        Augment whether **pile** from **from_stack** builds on **to_stack** to
        check **from_stack** len when both stack from **rows**.
        """
        if not super(Hemispheres_Hint, self).shall_move_pile(from_stack,
                                                       to_stack, pile, rpile):
            return False
        rows = self._stacks['set']['rows']
        if all(s in rows for s in (from_stack, to_stack,)):
            return len(from_stack.cards) == 1
        return True


class BigBen_Talon(stack.DealRowTalon):

    @property
    def _piles(self):
        """
        _piles -> tup

        :return: deal Game.s.rows until last then Game.s.rows [1:8]
        :rtype: tuple
        """
        return [s for s in self.game.s['rows']
                  if len(s.cards) < s.cards.cap['min_cards']]

    def deal_cards(self, sound=False):
        """
        deal_cards([sound:bool=False]) -> None

        Deal cards for Game.talon_deal() to other piles. Deal num_cards to
        waste pile.

        :keyword boolean sound: sound fx?
        """
        if not self.cards:
            return 0
        rows = self._piles
        if not rows:
            game = self.game
            if game.can_play_sound and sound:
                game._play_sound('dealwaste')
            game._move_do(a_move.AFlipAndMoveMove(self, game.s['wastes'][-1],
                                                  frames=4),
                           reset=True)  # low-level
            return 1
        # deal to the rows
        if game.can_play_sound and sound:
            game._play_sound('deal')
        ncards = 0
        while min(self.cards, len(rows)):
            ncards += self.dealRowAvail(rows=rows, sound=False)
            rows = self._piles
        return ncards


class Hemispheres_RowStack(stack.FromWasteBuildMethod, stack.SC_RowStack):

    @property
    def _otherRow(self):
        """
        Piles are from the other 6 piles _row_. Piles are slice 1st 6, 2nd 6.

        :return: slice from other 6 piles or empty tuple
        :rtype: tuple
        """
        rows = self.game.s['rows']
        if self in rows[:6]:
            return rows[:6]
        if self in rows[6:]:
            return rows[6:]
        return ()

    @property
    def _isInFromStacks(self):
        """
        Piles cards must be played from _waste_ or _otherRow.

        :return: parent sequence and _otherRow()
        :rtype: tuple
        """
        return (super(Hemispheres_RowStack, self)._isInFromStacks +
                self.otherRow())

    def _canSwapPair(self, from_stack):
        """
        Swap cards played from _otherRow when both have 1 card and color
        matches other pile.cap['base_color'].

        :param object from_stack: pile that held sequence.
        :return: pair can swap.
        :rtype: boolean
        """
        if not from_stack in self._otherRow(from_stack):
            return False
        if not all(len(c) == 1 for c in (self.cards, from_stack.cards,)):
            return False
        return (from_stack.BASECARD == self.cap['base_color'] and
                self.BASECARD == from_stack.cap['base_color'])

    def cardsBuild(self, from_stack, cards):
        """
        Check cards can swap, then build if cards _isInFromStacks and is
        same color as cap['base_color'].

        :param object from_stack: pile that held sequence.
        :param sequence cards: sequence.
        :return: sequence accepted?
        :rtype: boolean
        """
        if self._canSwapPair(from_stack):
            return True
        if not super(Hemispheres_RowStack, self).cardsBuild(from_stack,
                                                            cards):
            return False
        return cards[0]['color'] == self.cap['base_color']

    def move_pile(self, ncards, to_stack, **kwargs):
        """
        move_pile(ncards:int, stack:Stack[, *animate keywords* {frames:int=-1,
          shadow:int=-1}) -> None

        Peform parent move_pile() when play no _canSwapPair() otherwise
        override with _do_swap_pair().
        """
        if self._canSwapPair(to_stack):
            assert ncards == 1
            self.game._move_do(a_move.ASwapPairMove(self, to_stack, **kwargs),
                               reset=True)  # low level
        else:
            super(Hemispheres_RowStack, self).move_pile(ncards, to_stack,
                                                        **kwargs)


class BigBen_RowStack(stack.SS_RowStack):

    build_after = 3

    def _build_sequence(self, cards):
        """
        _build_sequence(cards:seq) -> bool

        Allow building parent sequence when build_after is pile cards.

        :param sequence cards: cards from sending pile
        :return: accept card sequence acccording to *capabilities*?
        :rtype: boolean
        """
        return (len(self.cards) >= self.build_after and
                super(BigBen_RowStack, self).build_sequence(cards))


class Clock_RowStack(stack.RK_RowStack):

    @property
    def _num_face_down(self):
        """
        _num_face_down() - > int

        :return: num face down cards on pile.
        :rtype: integer
        """
        return sum(int(not c.face_up) for c in self.cards)

    def move_pile(self, ncards, to_stack, frames=0, **kw):
        """
        move_pile(ncards:int, to_stack:Pile[, *animate keywords*]) -> None

        Peform _swapPairMove() always.
        """
        self._swap_pair(ncards, to_stack, frames=frames, **kw)

    @state.move_state('fill')
    def _swap_pair(self, ncards, to_stack, **kw):
        """
        Swap card and place under to stack face down. Flip and play from stack.

        .. \_swap_pair(ncards:int, to_stack:Pile[, *animate keywords*]) -> None
        """
        game = self.game
        game._move_do(a_move.AMoveMove(ncards, self, to_stack, **kw),
                      reset=True)  # low level
        game._move_do(a_move.AInnerMove(to_stack,
                                        from_pos=to_stack.index(stack.TOPCARD),
                                        to_pos=to_stack._num_face_down, **kw),
                      reset=True)  # low level
        game._move_do(a_move.AFlipAndMoveMove(to_stack, self, **kw),
                       reset=True)  #low level
        self.fill_stack()

    def fill_stack(self):
        """
        Perfom action after a move pile.

        Overide to auto move any KING as top card.

        """
        if self._num_face_down == 0:
            return
        topcard = self.TOPCARD
        if topcard and topcard.face_up and topcard['rank'] == cs.KING:
            game = self.game
            # place bottom. Final flip top when face down.
            game._move_do(a_move.AInnerMove(self,
                                        from_pos=self.index(stack.TOPCARD),
                                        to_pos=self._num_face_down, **kw),
                          reset=True)  # low level
            if not self.TOPCARD.face_up:
                self.flip_card()
            self.fill_stack()

    def cardFlips(self):
        """
        card_flips([animation:bool=False]) -> None

        Overide to not flip top card of pile.
        """
        return False


class GrandfathersClock(game.Game):
    """
    Finish cards on _foundation_ within 1 turn.

    _row_
      Pile 8 over 2 row E. Init deal 5 card. Build down in rank alone. Play
      top.

    _foundation_
      Pile 12 around circle E. Init deal base from from 9:00 pile — TWO clubs,
      THREE hearts, FOUR spades, FIVE diamonds, SIX clubs, SEVEN hearts, EIGHT
      spades, NINE Diamonds, TEN clubs, JACK hearts, QUEEN spades, KING
      diamonds. Build up in rank by same suit wrap. Play none.

    note::
      ⟪highlight_play⟫, ⟪autoflip⟫, ⟪autodrop⟫, ⟪quickplay⟫ disabled.

    seealso::
      http://en.wikipedia.org/wiki/Big_Ben_%28solitaire%29
    ------
    :cvar Stack _talon_: stack.InitialDealTalon
    :cvar Stack _foundation_: stack.SS_Foundation (mod=13, max_move=0)
    :cvar Stack _row_: stack.RK_RowStack (max_move=1, max_accept=1)
    :cvar Hint _hint_: hint.DropbyCautiousHint
    """
    __info__ = dict(id=261, name='Grandfatherʼs Clock', game_type=(GT.ONE_DECK
                    | GT.OPEN | GT.KDE), decks=1, skill_level=SL.BALANCED,
                    version='2.01')
    __author__ = 'Markus Oberhumer'
    __version__ = 7.70

    _talon_ = stack.InitialDealTalon
    _foundation_ = StackWrapper(stack.SS_Foundation, mod=13, max_move=0)
    _row_ = StackWrapper(stack.RK_RowStack, max_move=1, max_accept=1)
    _hint_ = DropbyCautiousHint

    def _create_game(self, rows=8, playcards=9, **kw):
        l, s = layout.Layout(self), self.s
        dy = max(3 * l.YS / 2 + l.CH, l._get_stack_height(playcards))
        self.table_size = ((rows / 2 + 5) * l.XS + l.XM, l.YM + 2 * dy)
        for x, y in l.col_block_iter(l.XM, l.YM, npiles=rows, ncols=rows / 2,
                                     ycards=playcards):
            s['rows'].append(self._row_(x, y, game=self))
        dx, dy = x - l.XM / 2, l.YM + dy - l.HCH
        self._set_region(s['rows'][:4], self._region(w=dx, h=dy))
        self._set_region(s['rows'][4:], self._region(y=dy, w=dx))
        piles = [(x, y,) for x, y in l.round_iter(12, rows / 2 * l.XS + l.XM)]
        for i, rank, suit in zip(range(9, -1, -1) + [11, 10],
                                 range(cs.TWO, cs.KING + 1), l.SUIT * 3):
            x, y = piles[i]
            s['foundations'].append(self._foundation_(x, y, game=self, suit=suit,
                                                   base_rank=rank))
        s['talon'] = self._talon_(self.width - l.XS, self.height - l.YS,
                               game=self)
        l.defaultStackGroups()
        return

    def _pack_place(self, cards):
        """
        _pack_place(cards:seq(Card ...)) -> seq(Card ...)

        Overide to return TWO club, THREE heart, FOUR spade, FIVE diamond,
        SIX club, SEVEN heart, EIGHT spade, NINE Diamond, TEN club, JACK heart,
        QUEEN spade, KING diamond on top by rank, suit for _foundation_ deal.
        """
        clocks = []
        ranks = self['ranks'][1:]
        check_ranks = (ranks[0::4], ranks[1::4], ranks[2::4], ranks[3::4],)
        for c in cards[:]:
            if c['rank'] in check_ranks[c['suit']]:
                clocks.append(c)
                cards.remove(c)
        clocks.sort(lambda a, b: cmp(b['rank'], a['rank']))
        return cards + cards

    def _start(self, rows=5, flip=True, **kw):
        self.s['talon'].dealRow(rows=self.s['foundations'])
        for i in range(rows - 1):
            self.s['talon'].dealRow(flip=flip, frames=0)
        self._play_sound('deal')
        self.s['talon'].dealRow(flip=flip)

    @property
    def _highlight_piles(self):
        """
        Return piles to highlight for possible move.

        :return: empty.
        :rtype: tuple
        """
        return ()

    def _autopiles(self, event=None):
        """
        Return piles for auto or quick move.

        Overide to disable autoflip, autodrop, quickplay.

        .. \_autopiles(self, event=None) -> seq(seq(Pile ...), seq(Pile ...),
             seq(Pile ...))
        """
        return autostacks.none()


class BigBen(GrandfathersClock):
    """
    Finish cards on _foundation_ within 1 turn.

    _row_
      Pile 12 over 2 row E. Init deal 3 card. Build down in rank by same suit
      wrap. Play top.

    _talon_
      Pile 1 SE. Deal so each has 3 card on _row_ with less than 3 card, else
      deal 1 card on _waste.

    _waste_
      Pile 1 W _talon_. Build none. Play top.

    _foundation_
      Pile 12 around circle E. Init deal base from from 9:00 pile — TWO clubs,
      THREE hearts, FOUR spades, FIVE diamonds, SIX clubs, SEVEN hearts, EIGHT
      spades, NINE Diamonds, TEN clubs, JACK hearts, QUEEN spades, KING
      diamonds. Build up in rank by same suit wrap. Play none.

    note::
      ⟪highlight_play⟫, ⟪autoflip⟫, ⟪autodrop⟫, ⟪quickplay⟫, ⟪autodeal⟫
      disabled.

    seealso::
      http://en.wikipedia.org/wiki/Big_Ben_%28solitaire%29
    ------
    :cvar Stack _talon_: BigBen_Talon
    :cvar Stack _waste_: stack.WasteStack
    :cvar Stack _foundation_: stack.SS_Foundation (mod=13, max_move=0)
    :cvar Stack _row_: BigBen_RowStack (max_move=1, mod=13)
    :cvar Hint _hint_: hint.DropbyCautiousHint
    """
    __info__ = dict(id=697, name='Big Ben', game_type=GT.TWO_DECK, decks=2,
                    skill_level=SL.BALANCED, version='1.00fc')
    __author__ = 'Skomoroh'
    __version__ = 7.70

    _talon_ = BigBen_Talon
    _waste_ = stack.WasteStack
    _row_ = StackWrapper(BigBen_RowStack, max_move=1, mod=13)

    def _create_game(self, **kw):
        kw.setdefault('rows', 12)
        l, s = super(BigBen, self)._create_game, self.s
        for _foundation_ in s._foundations_:
            cap = _foundation_.cap
            cap['max_cards'] = cap['base_rank'] <= 4 and 8 or 9
        l.set_ncards_text(s['talon'], 'n')
        s['wastes'].append(self._waste_(s['talon'].x - l.XS, s['talon'].y,
                                        game=self))
        l.set_ncards_text(s['wastes'][-1], 'n')
        l.defaultStackGroups()
        return

    def _start(self, rows=3, **kw):
        super(BigBen, self)._start(**kw)

    def _auto_deal(self, sound=True):
        # don't deal a card to the waste if the waste is empty
        return 0


class Clock(game.Game):
    """
    Finish cards on _foundation_ within 1 turn.

    _rows_
      Pile 12 around circle with 1 center E. Build up in same rank by alt
      color. Base from 1:00 ACE, TWO, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT,
      NINE, TEN, JACK, QUEEN around circle. Base KING center. diamonds. Play
      top. Cards built play under stack and top card flips open.

    note::
      ⟪highlight_play⟫, ⟪autoflip⟫, ⟪autodrop⟫, ⟪quickplay⟫ disabled.

    ------
    :cvar Stack _talon_: stack.InitialDealTalon
    :cvar Stack _rows_: Clock_RowStack (max_move=0), Clock_RowStack
      (max_move=1)
    """
    __info__ = dict(id=737, name='Clock', game_type=(GT.ONE_DECK | GT.GNOME),
                    decks=1, skill_level=SL.LUCK, altnames=('Travellers',),
                    version='1.10fc')
    __author__ = 'Skomoroh'
    __version__ = 7.70

    _talon_ = stack.InitialDealTalon
    _rows_ = (StackWrapper(Clock_RowStack, max_move=0),
              StackWrapper(Clock_RowStack, max_move=1),)

    def _create_game(self):
        l, s = layout.Layout(self), self.s
        self.table_size = (l.XM + 8 * l.XS, l.YM + 4 * l.YS)
        piles = [(x, y,) for x, y in l.round_iter(12, dx=l.XM + 2 * l.XS)]
        for i, rank in zip(range(5, -1, -1) + range(11, 5, -1), l.RANK[:-1]):
            x, y = piles[i]
            s['rows'].append(self._row_[0](x, y, game=self, rank=rank,
                                     offset=(0, 0)))
        y = s.rows[8].y
        s['rows'].append(self._row_[1](x, y, game=self, rank=cs.KING,
                                    offset=(0, 0)))
        x, y = l.XM, l.YM
        s['talon'] = self._talon_(x, y, game=self)
        for i in range(2):
            s['internals'].append(stack.InvisibleStack(game=self))
        l.defaultStackGroups()
        return l

    def _start(self, rows=4, **kw):
        for i in range(rows - 1):
            self.s['talon'].dealRow(frames=0, flip=False)
        self._play_sound('deal')
        self.s['talon'].dealRow(flip=False)
        self.flip(self.s['rows'][-1])
        self.s['rows'][-1]._fill_stack()

    @property
    def is_complete(self):
        return all(r.TOPCARD.face_up for r in self.s['rows'])

    @property
    def _highlight_piles(self):
        """
        Return piles to highlight for possible move.

        :return: empty.
        :rtype: tuple
        """
        return ()

    def _autopiles(self, event=None):
        """
        Return piles for auto or quick move.

        Overide to disable autoflip, autodrop, quickplay.

        .. \_autopiles(self, event=None) -> seq(seq(Pile ...), seq(Pile ...),
             seq(Pile ...))
        """
        return autostacks.none()


class Dial(game.Game):
    """
    Finish cards on _foundation_ within 2 turn.

    _talon_
      Pile 1 SE. Deal _waste.

    _waste_
      Pile 1 W _talon_. Build none. Play top.

    _foundation_
      Pile 12 around circle with 1 center E. Build up in same rank by alt
      color. Base from 1:00 ACE, TWO, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT,
      NINE, TEN, JACK, QUEEN around circle. Base KING center. diamonds. Play
      none.
    ------
    :cvar Stack _talon_: stack.WasteTalon (max_rounds=2)
    :cvar Stack _waste_: stack.WasteStack
    :cvar Stack _foundation_: stack.AC_Foundation (dir=0, max_cards=4,
      max_move=0)
    """
    __info__ = dict(id=682, name='Dial', game_type=GT.ONE_DECK, decks=1,
                    redeals=1, skill_level=SL.LUCK, version='1.00fc')
    __author__ = 'Skomoroh'
    __version__ = 7.70

    _talon_ = StackWrapper(stack.WasteTalon, max_rounds=2)
    _waste_ = stack.WasteStack
    _foundation_ = StackWrapper(stack.AC_Foundation, dir=0, max_cards=4,
                                max_move=0)

    def _create_game(self):
        l, s = layout.Layout(self), self.s
        self.table_size = (l.XM + 8 * l.XS, l.YM + 4 * l.YS)
        piles = [(x, y,) for x, y in l.round_iter(12, dx=l.XM + 2 * l.XS)]
        for i, rank in zip(range(5, -1, -1) + range(11, 5, -1), l.RANK[:-1]):
            x, y = piles[i]
            s['foundations'].append(self._foundation_(x, y, game=self,
                                                   base_rank=rank))
        y = s['foundations'][8].y
        s['foundations'].append(self._foundation_(x, y, game=self,
                                               base_rank=cs.KING))
        x, y = l.XM, l.YM
        s['talon'] = self._talon_(x, y, game=self)
        l.set_ncards_text(s['talon'], 's')
        l.set_rounds_text(s['talon'], 'sss')
        s['wastes'].append(self._waste_(x + l.XS, y, game=self))
        l.set_ncards_text(s['wastes'][-1], 's')
        l.defaultStackGroups()
        return l

    def _start(self):
        self._play_sound('deal')
        self.s['talon'].deal_cards()


class Hemispheres(game.Game):
    """
    Finish cards on _foundation_ within 1 turn.

The Aces of Diamonds and Hearts and the King of Clubs and Spades are
      dealt on the <link xref='term.space#foundation'/> over two rows. A <link
      xref='term.pile#stack'/> on the top and bottom are dealt the Ace of
      Clubs and Spades then a <link xref='term.pile#stack'/> on the left and
      right are dealt the King of Diamonds and Hearts are dealt on the <link
      xref='term.space#reserve'/>. Three <link role='set'
      xref='term.pile#stack'/> around each corner are dealt one card each on
      the <link xref='term.space#tableau'/>. The <link
      xref='term.space#talon'/> and the <link xref='term.space#waste'/> are
      vertical in the upper left.

    _row_
      Pile 12 around corner _foundation_ E W N S. Init deal 3 card. Build in
      rank by same color. N down by red. S up by black. Play top. Cards from
      wrong color may swap with another wrong color. Gap deal 1 card from
      _waste_.

    _reserve_
      Pile 4 E W N S _foundation_. Init deal ACE clubs spades N NS and KING
      hearts diamonds E W. Build none. Play top.

    _talon_
      Pile 1 NW. Deal so each has 3 card on _row_ with less than 3 card, else
      deal 1 card on _waste.

    _waste_
      Pile 1 E _talon_. Build none. Play top.

    _foundation_
      Pile 8 over 2 row center. Init deal base N ACE heart diamonds and S KING
      clubs spades. Build in rank by same suit wrap. N up. S down. Play none.
    ------
    :cvar Stack _talon_: BigBen_Talon
    :cvar Stack _waste_: stack.WasteStack
    :cvar Stack _foundation_: stack.SS_Foundation (mod=13, max_move=0)
    :cvar Stack _row_: BigBen_RowStack (max_move=1, mod=13)
    :cvar Hint _hint_: hint.DropbyCautiousHint
    """
    __info__ = dict(id=690, name='Hemispheres', game_type=GT.TWO_DECK,
                    decks=2, skill_level=SL.BALANCED,
                    altnames=('The Four Continents',), version='1.00fc')
    __author__ = 'Skomoroh'
    __version__ = 7.70

    _talon_ = stack.WasteTalon
    _waste_ = stack.WasteStack
    _foundations_ = (StackWrapper(stack.SS_Foundation, max_move=0),
                     StackWrapper(stack.SS_Foundation, max_move=0,
                                  base_rank=cs.KING, dir=-1),)
    _rows_ = (StackWrapper(Hemispheres_RowStack, base_color=cs.RED, max_move=1),
              StackWrapper(Hemispheres_RowStack, base_color=cs.BLACK,
                           max_move=1, dir=1),)
    _reserves_ = StackWrapper(stack.BasicRowStack, max_accept=0)
    _hint_ = Hemispheres_Hint

    def _create_game(self):
        l, s = layout.Layout(self), self.s
        self.table_size = (l.XM + 19 * l.HXS, l.YM + 5 * l.YS)
        s['internals'].append(stack.InvisibleStack(game=self))
        ddx = l.XM + 3 * l.HXS
        for dx, dy in ((0, 2), (14, 2), (7, 0), (7, 4),):
            x, y = l.delta_coords(x=ddx, dx=dx, dy=dy, fx=2)
            s['reserves'].append(self._reserves_(x, y, game=self,))
        xdeltas = [f for f in range(1, 4)]
        ydeltas = ([10, 5, 3, 3, 5, 10], [30, 35, 38, 38, 35, 30])
        ddx += l.XS / 2
        for i, _rows_ in zip(range(2), self._rows_):
            for dx, dy in zip(xdeltas, ydeltas[i]):
                x, y = l.delta_coords(x=ddx, dx=dx, dy=dy, fy=10)
                s['rows'].append(self._row_(x, y, game=self, offset=(0, 0)))
        dx, y = ddx + 2 * l.XS, l.YM + 3 * l.YS / 2
        for suits, _foundation_ in zip(((2, 3,) * 2), ((0, 1,) * 2),
                                        self._foundations_):
            for suit, (x, y) in zip(suits, l.row_iter(dx, 4)):
                s['foundations'].append(_foundation_(x, y, game=self, suit=suit))
            y += l.YS
        x, y = l.XM, l.YM
        s['talon'] = self._talon_(x, y, game=self)
        l.set_ncards_text(s['talon'], 'ne')
        s['wastes'].append(self._waste_(x, y + l.YS, game=self))
        l.set_ncards_text(s['wastes'] - 1, 'ne')
        l.defaultStackGroups()
        return l

    def _pack_place(self, cards):
        """
        _pack_place(cards:seq(Card ...)) -> seq(Card ...)

        Overide to return ACE club spade and KING heart diamond by rank, deck,
        suit reverse below all ACE heart diamond and KING club spade on top by
        rank, suit for _foundation_ deal.
        """
        _SORT = place._SORT
        f_cards = []
        r_cards = []
        for c in cards[:]:
            if ((c['rank'] == cs.ACE and c['color'] == cs.RED) or
                (c['rank'] == cs.KING and c['color'] == cs.BLACK)):
                cards.remove(c)
                f_cards.append(c)
            if c['rank'] in (cs.ACE, cs.KING,) and c['deck'] == 0:
                cards.remove(c)
                r_cards.append(c)
        f_cards.sort(cmp=lambda c1, c2: cmp(_SORT(c1), _SORT(c2)),
                              reverse=True)
        r_cards.sort(cmp=lambda c1, c2: cmp(_SORT(c1), _SORT(c2)))
        return cards + r_cards + f_cards

    def _start(self):
        self.s['talon'].dealRow(rows=self.s['foundations'], frames=0)
        self.s['talon'].dealRow(rows=self.s['reserves'])
        self._play_sound('deal')
        self.s['talon'].dealRow()
        self.s['talon'].deal_cards()

    @state.move_state('fill')
    def _auto_fill(self, stack):
        """
        Fill stack if _row_ when gap from _waste_.

        *Parameters*:
           stack : Stack
             pile just played
        """
        fill.fromWaste(self, stack, self.s['rows'])


PROVIDES = [GrandfathersClock, Dial, Hemispheres, BigBen, Clock]